<?php

namespace App\Lib\Uploads;


use App\Jobs\Attachment\VideoCosReviewSubmit;
use App\Lib\WeApp\WeApp;
use App\Wen\Utils\FieldUtils;
use App\Wen\Utils\Settings;
use App\Models\WxAttachment;
use App\Wen\Utils\UserUtils;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Intervention\Image\Facades\Image;
use Qcloud\Cos\Client;

/**
 * 公共上传类
 * Class UploadHandler
 * @package App\Lib\Uploads
 */
class UploadHandler
{
    /**
     * 文件上传
     * @param $filePath
     * @return mixed
     */
//    public static function upload($filePath)
//    {
//        $storePath = date('Y/m/d', time());
//        $disk = config('admin.upload.disk');
//        $path = $filePath->store($storePath, $disk);
//        $domain = config('filesystems.disks.' . $disk . '.domains.https');
//        if (_empty_($model)) {
//            $model = new WxAttachment();
//            $model->path = $path;
//            $model->save();
//        }
//
//        return $domain . $path;
//    }

    /**
     * @param $file
     * @param int $uid
     * @param int $state 0: 待使用 1：已使用
     * @return array
     */
    public static function handle($file, $uid = 0, $state = 1, $scene = 0, $fileName = '')
    {
        if(_empty_($file)){
            return null;
        }
        $ext = $file->extension() ?? $file->getClientOriginalExtension();
        $the_img = null;
        $last_width = 0;
        $last_height = 0;
        $image_qua = 100;
        if($uid > 0 && in_array($ext, ['png', 'jpg', 'jpeg'])){
            $the_img = Image::make($file)->orientate();
            $mime = $the_img->mime();
            if($mime == 'image/gif'){
                $the_img = null;
            }else if($mime == 'image/jpeg' || $mime == 'image/png' || $mime == 'image/jpg'){
                $image_qua = Settings::get('app_upload_image_slimming', 100, true);
                $image_max_width = Settings::get('app_upload_image_max_width', 800, true);
                $img_width = $the_img->getWidth();
                $img_height = $the_img->getHeight();
                if(Settings::get('is_image_detection') == 1){
                    $the_img->backup();
                    $ak = (new WeApp())->getAccessToken();
                    // 微信安全检测,等比缩小
                    if($ak){
                        $proportion1 = $img_width / 600;
                        $proportion2 = $img_height / 800;
                        if($proportion1 > $proportion2){
                            $new_height = (int)( (600 * $img_height) / $img_width );
                            $atack_img = $the_img->resize(600, $new_height);
                        }else{
                            $new_width =  (int)((800 * $img_width) / $img_height);
                            $atack_img = $the_img->resize($new_width, 800);
                        }


                        if($atack_img){
                            $post = Http::attach(
                                'attachment', $atack_img->stream(null, 90)->getContents(), 'attach.jpg'
                            )->post('https://api.weixin.qq.com/wxa/img_sec_check?access_token='.$ak);
                            if($post->successful()){
                                $atack_res = $post->json();
                                if($atack_res['errcode'] != 0){
                                    if($atack_res['errcode'] == 87014){
                                        if($uid > 1){
                                            _limit_user('upload:risk:img', $uid, 3, '上传的图片包含违规内容');
                                            UserUtils::assistant_notice($uid, '图片检测出一个违规内容，已自动清理，请勿上传违规文件'.$post->body());
                                        }
                                        UserUtils::assistant_notice('admin', '用户（<a href="/pages/user/user?id='.$uid.'" target="_blank">id：'.$uid.'</a>）图片检测出一个违规内容，已自动清理'.$post->body());
                                        throw new \Exception('图片检测出一个违规内容，已自动清理，请勿上传违规文件');
                                    }else if($atack_res['errcode'] == 87015){
                                        _logger_(__file__, __line__, '超出可检测大小。height: '.$atack_img->getHeight() .' width: '.$atack_img->getWidth());
//                                        throw new \Exception('超出可检测大小。');
                                    }
                                }
                            }
                        }
                    }
                    $the_img->reset();
                }

                // 等比缩小
                if ($image_max_width != 10000 && ($img_width > $image_max_width)) {
                    // 等比缩放，需要计算宽度缩放的比例，再计算出缩放后的图片高度
                    $proportion = $img_width / $image_max_width;
                    $height = ceil($img_height / $proportion);
                    $the_img = $the_img->resize($image_max_width, $height);
                    $img_width = $the_img->getWidth();
                    $img_height = $the_img->getHeight();
                }

                // 水印处理
                $mask_type = Settings::get('app_upload_image_mask_type', 0, true);
                if($scene == 3 && $mask_type == 1 && $img_width >= 200){
                    $mask_png = Settings::get('app_upload_image_mask_img', '', true);
                    if(!file_exists(storage_path($mask_png))){
                        UserUtils::assistant_notice('admin', '您的水印图片丢了，快去服务器看看，你配置的水印地址为：'.storage_path($mask_png));
                    }else{
                        $mask_pos = Settings::get('app_upload_image_mask_pos', 5, true);
                        $mask_size = Settings::get('app_upload_image_mask_rate', 10, true);
                        $opacity = Settings::get('app_upload_image_mask_opacity', 100, true);
                        $mask_pos_ = ['1'=>'top-left', '2'=>'top', '3'=>'top-right', '4' => 'left', '5'=>'center', '6'=>'right', '7'=>'bottom-left', '8'=>'bottom', '9'=>'bottom-right'][$mask_pos];
                        if($mask_png){
                            $mask = Image::make(storage_path($mask_png))->opacity($opacity);
                            $mask_width = $mask->getWidth();
                            $mask_height = $mask->getHeight();
                            // use callback to define details
                            if($img_width > $img_height){

                                if($mask_width > $mask_height){
                                    $mask_new_height = (int)($img_height * $mask_size * 0.01);
                                    $mask_new_width = (int)(($mask_new_height * $mask_width) / $mask_height);
                                    $mask = $mask->resize($mask_new_width, $mask_new_height);
                                    $the_img->insert($mask, $mask_pos_);
                                }else{
                                    $mask_new_width = (int)($img_height * $mask_size * 0.01);
                                    $mask_new_height = (int)( ($mask_new_width * $mask_height) / $mask_width );
                                    $mask = $mask->resize($mask_new_width, $mask_new_height);
                                    $the_img->insert($mask, $mask_pos_);
                                }
                            }else{
                                if($mask_width > $mask_height){
                                    $mask_new_height = (int)($img_width * $mask_size * 0.01);
                                    $mask_new_width = (int)(($mask_new_height * $mask_width) / $mask_height);
                                    $mask = $mask->resize($mask_new_width, $mask_new_height);
                                    $the_img->insert($mask, $mask_pos_);
                                }else{
                                    $mask_new_width = (int)($img_width * $mask_size * 0.01);
                                    $mask_new_height = (int)( ($mask_new_width * $mask_height) / $mask_width );
                                    $mask = $mask->resize($mask_new_width, $mask_new_height);
                                    $the_img->insert($mask, $mask_pos_);
                                }

                            }
                        }
                    }
                }
            }else{
                $the_img = null;
            }
        }

        if($the_img){
            $last_width = $the_img->getWidth();
            $last_height = $the_img->getHeight();
        }else if($uid == -1 && in_array($ext, ['png', 'jpg', 'jpeg'])){
            // 后台上传
            $the_img = Image::make($file);
            $last_width = $the_img->getWidth();
            $last_height = $the_img->getHeight();
        }
        if($uid == -1){
            $uid = 0;
        }

        // 上传方式
        $ossType = Settings::get('ossType');
        // 路径
        $storePath = date('Y/m/d');
        // 文件名称
        if(_empty_($fileName)){
            $fileName = md5(uniqid()) . '.' . $ext;
        }
        $key =  $storePath . '/' . $uid . '/' . $fileName;
        // 本地上传
        // 腾讯云cos

        $cosConfig = Settings::get('cosv5', []);
        $cosClient = new Client(array(
            'region' => $cosConfig['region'],
            'credentials' => array(
                'secretId' => $cosConfig['secretId'],
                'secretKey' => $cosConfig['secretKey'],
            )
        ));
        ### 上传文件流
        try {
            $result = $cosClient->putObject(array(
                'Bucket' => $cosConfig['bucket'] . '-' . $cosConfig['appId'],
                'Key' => $key,
                'Body' => $the_img ? ($the_img->stream(null, $image_qua)->getContents()) : fopen($file, 'rb') ));
            $location = $cosConfig['domain'] . '/' . $key;
        } catch (\Exception $e) {
            if(strpos($e->getMessage(), 'The Signature you specified is invalid') >= 0){
                _logger_(__file__, __Line__, '您的cos配置的SecretId和SecretKey中，存在错误，请检查');
            }else{
                _logger_(__file__, __line__, $e->getMessage());
            }
            return null;
        }



        // 保存到附件表
        $model = new WxAttachment();
        $model->user_id = $uid;
        $model->path = $key;
        $model->domain = $cosConfig['domain'];
        $model->store_type = $ossType;

        $types_str = implode('|', FieldUtils::getAttachmentTypes());
        preg_match('/\.('.$types_str.')$/', $key, $matchs);
        if($matchs && _array_key($matchs, 1, null)){
            $model->type = $matchs[1];
        }else{
            $model->type = '';
        }
        if(in_array($model->type, ['mp4', 'mp3'])){
            $model->cos_review = 4;
        }

        $model->state = $state;

        $model->save();

        if($last_width > 0 && $last_height > 0){
            Cache::put($location, json_encode(['width'=>$last_width, 'height'=>$last_height]), 3600 * 5);
        }

        if($model->cos_review == 4){
            VideoCosReviewSubmit::dispatch($model->id);
        }


        return [
            'key' => $key,
            'name' => $fileName,
            'path' => $storePath,
            'store_type' => $ossType,
            'url' => $location
        ];

    }

    public static function img($the_img, $ext = 'png'){
        // 上传方式
        $ossType = Settings::get('ossType');
        // 路径
        $storePath = date('Y/m/d');
        // 文件名称
        $fileName = md5(uniqid()) . '.' . $ext;
        $key = $storePath . '/' . $fileName;
        // 本地上传
        // 腾讯云cos

        $cosConfig = Settings::get('cosv5', []);
        $cosClient = new Client(array(
            'region' => $cosConfig['region'],
            'credentials' => array(
                'secretId' => $cosConfig['secretId'],
                'secretKey' => $cosConfig['secretKey'],
            )
        ));
        ### 上传文件流
        try {
            $result = $cosClient->putObject(array(
                'Bucket' => $cosConfig['bucket'] . '-' . $cosConfig['appId'],
                'Key' => $key,
                'Body' => $the_img->stream(null, 100)->getContents() ));
            $location = $cosConfig['domain'] . '/' . $key;
        } catch (\Exception $e) {
            _logger_(__file__, __line__, $e->getMessage());
            return null;
        }


        // 保存到附件表
        $model = new WxAttachment();
        $model->user_id = 0;
        $model->path = $key;
        $model->domain = $cosConfig['domain'];
        $model->store_type = $ossType;
        $model->state = 1;
        $model->save();

        return [
            'key' => $key,
            'name' => $fileName,
            'path' => $storePath,
            'store_type' => $ossType,
            'url' => $location
        ];
    }


    // 上传二进制图片
    public static function binary($binary, $ext = 'png'){
        // 上传方式
        $ossType = Settings::get('ossType');
        // 路径
        $storePath = date('Y/m/d');
        // 文件名称
        $fileName = md5(uniqid()) . '.' . $ext;
        $key = $storePath . '/' . $fileName;
        // 本地上传
        // 腾讯云cos

        $cosConfig = Settings::get('cosv5', []);
        $cosClient = new Client(array(
            'region' => $cosConfig['region'],
            'credentials' => array(
                'secretId' => $cosConfig['secretId'],
                'secretKey' => $cosConfig['secretKey'],
            )
        ));
        ### 上传文件流
        try {
            $result = $cosClient->putObject(array(
                'Bucket' => $cosConfig['bucket'] . '-' . $cosConfig['appId'],
                'Key' => $key,
                'Body' => $binary ));
            $location = $cosConfig['domain'] . '/' . $key;
        } catch (\Exception $e) {
            _logger_(__file__, __line__, $e->getMessage());
            return null;
        }


        // 保存到附件表
        $model = new WxAttachment();
        $model->user_id = 0;
        $model->path = $key;
        $model->domain = $cosConfig['domain'];
        $model->store_type = $ossType;
        $model->state = 1;
        $model->save();

        return [
            'key' => $key,
            'name' => $fileName,
            'path' => $storePath,
            'store_type' => $ossType,
            'url' => $location
        ];
    }

    public static function frozen(WxAttachment $attachment, $save = true, $cos_review = 2){
        if(_empty_($attachment)){
            return false;
        }
        $key = $attachment->path;
        // 上传方式
        $ossType = Settings::get('ossType');
        // 本地上传
        if ($ossType == 'local') {
            if(file_exists(storage_path($key))){
                unlink(storage_path($key));
                return true;
            }
        }
        // 腾讯云cos
        if ($ossType == 'cosv5') {
            $cosConfig = Settings::get('cosv5', []);
            $cosClient = new Client(array(
                'region' => $cosConfig['region'],
                'credentials' => array(
                    'secretId' => $cosConfig['secretId'],
                    'secretKey' => $cosConfig['secretKey'],
                )
            ));
            ### 冻结文件
            try {
                $result = $cosClient->putObjectAcl([
                    'Bucket' => $cosConfig['bucket'] . '-' . $cosConfig['appId'],
                    'Key' => $key,
                    'ACL' => 'private',
                ]);
                if($save){
                    $attachment->state = 3;
                    $attachment->cos_review = $cos_review;
                    $attachment->save();
                }
                return true;
            } catch (\Exception $e) {
                _logger_(__file__, __line__, $e->getMessage());
            }
        }
        return false;
    }

    public static function del(WxAttachment $attachment, $save = true, $cos_review = -1){

        if(_empty_($attachment)){
            return false;
        }
        $key = $attachment->path;
        // 上传方式
        $ossType = Settings::get('ossType');
        // 本地上传
        if ($ossType == 'local') {
            if(file_exists(storage_path($key))){
                unlink(storage_path($key));
                return true;
            }
        }
        // 腾讯云cos
        if ($ossType == 'cosv5') {
            $cosConfig = Settings::get('cosv5', []);
            $cosClient = new Client(array(
                'region' => $cosConfig['region'],
                'credentials' => array(
                    'secretId' => $cosConfig['secretId'],
                    'secretKey' => $cosConfig['secretKey'],
                )
            ));
            ### 删除文件
            try {
                $result = $cosClient->deleteObject(array(
                    'Bucket' => $cosConfig['bucket'] . '-' . $cosConfig['appId'],
                    'Key' => $key));
                if($save){
                    $attachment->state = 2;
                    if($cos_review >= 0 && in_array($cos_review, [0, 1, 2, 3, 4, 5])){
                        $attachment->cos_review = $cos_review;
                    }
                    $attachment->save();
                }
                return true;
            } catch (\Exception $e) {
                _logger_(__file__, __line__, $e->getMessage());
            }
        }
        return false;
    }

}
